#ifndef SERVERH
#define SERVERH
#include <map>
#include <list>
#include <string>
#include <gmMachine.h>
#include <gmUserObject.h>
#include <gmStringObject.h>
#include "sox.h"
#include "Player.h"
#include "Client.h"
#include "PlayerList.h"

class Server
{
protected:
    struct GMEvent {
        gmVariable          m_thisObject;
        gmFunctionObject*   m_function;
    };

    std::list<GMClient*>      m_unknownClients;
    gmMachine*              m_machine;
    GMPlayerList            m_players;
    sox::ListenSock*        m_listenSocket;

    std::map<int, std::map<int, GMEvent> >  m_eventHandlers;
    std::map<int, GMEvent>*                 m_currentEvent;

    bool m_isRunning;
    void ParseFirstPacket(GMClient* client, ByteStream& packet);
    void ParsePackage(Player* player, ByteStream& packet);
    bool PrepareEvent(int eventID);
    void SendAccount(GMPlayer* player);
    void CallEvent(gmVariable args[], int argc);
    void ClearEvents(int pluginID);
    GMPlayer* AllocPlayer(GMClient* client = NULL);
    void RegisterEventHandler(int pluginID, int eventID, const GMEvent& event);
    void End() {
        m_isRunning = false;
    }

public:
    enum {
        EVENT_NEW_CLIENT
    };

    Server();
    int Run(int argc, char* argv[]);

};

class GMServer:
    public Server
{
private:
    gmUserObject* m_userObject;
    static gmType   m_userType;
    static bool GM_CDECL GMTrace(gmMachine * a_machine, gmUserObject* a_object, gmGarbageCollector* a_gc, const int a_workLeftToGo, int& a_workDone);
    static void GM_CDECL GMOPDotGet(gmThread * a_thread, gmVariable * a_operands);
    static int GM_CDECL GMRegisterEvent(gmThread *a_thread);

public:
    gmUserObject* GetUserObject() {
        return m_userObject;
    }

    static gmType GetType() {
        return m_userType;
    }


    static void Register(gmMachine* machine);

};


#endif // SERVERH

